home *** CD-ROM | disk | FTP | other *** search
- #include <MacHeaders>
- #include <PictUtil.h>
-
-
-
- /* compile-time switches. during the course of developing this custom sampling method, we found it useful to have a
- bunch of debugging code that checks for invalid data structures compiled into strategic spots in the code. however,
- since the debugging code slows the method down by several orders of magnitude, we made all of it conditional on
- the following “debugging” flag. simply change the undef to a define and then all the debugging code will be compiled
- in to allow you to test your changes. */
-
- #undef debugging
-
-
-
- /* constants that we use throughout the code */
-
- #define emptyNode 0x8000 /* this indicates that either a child or a parent slot doesn’t point to any node */
- #define obsoleteNode 0xFFFF /* this value stored in the “children” field of a node, indicates that it needs to be removed */
- #define maximumLevel 8 /* this is the maximum number of levels that the octree covers */
-
-
-
- /* macros used for conditionally compiling debugging code */
-
- #ifdef debugging
- #define IfDebug(x, y) { if(x) DebugStr(y); }
- #define ValidateTree(x) ValidateOctree(x)
- #else
- #define IfDebug(x, y)
- #define ValidateTree(x)
- #endif
-
-
-
- /* the data structures used by this sampling method */
-
- typedef struct octreeNode {
- short children; /* count of how many leaves are filled */
- short parent;
- short leaf[8];
- } octreeNode;
-
- typedef struct octreeColor {
- long count;
- unsigned long totalRed; /* this total allows us to average all the components of this entry */
- unsigned long totalGreen;
- unsigned long totalBlue;
- short level;
- short next; /* color index of the next color at this level */
- short parent; /* node index of the node that owns this color */
- short padding; /* to make the structure long aligned */
- } octreeColor;
-
- typedef struct octree {
- short maximumNodes;
- short nodes;
- octreeNode *nodeBase;
- short maximumColors;
- short colors;
- octreeColor *colorBase;
- short validationCount;
- short colorList[maximumLevel + 1]; /* these are indexes into the first color entry at this level (zero is allocated, but unused)*/
- } octree;
-
-
- /*-------------------------------------------------------------------------------------------------------*/
- /* this is the code for a custom color sampling method that can be called by picture utilities to determine the best
- set of colors to use for a picture. it uses a data structure known as an octree to keep track of its colors following
- a method loosely described in Graphics Gems on page 287 by Michael Gervautz and Werner Purgathofer.
-
- picture utilities will store one long word for us and pass it to each of our routines, so we use this to store a handle
- to our main octree structure. we lock and dereference this handle upon entering each of the “public” routines that
- picture utilities calls and we unlock it upon exiting these routines. note that since we don’t allocate memory in any
- of the internal octree routines, we wouldn’t really need to lock this handle down, but locking it doesn’t cost us any
- measurable time and allows us to change the internals later to allocate memory without being bitten by a memory
- bug.
-
- we also have two other handles; one for the maximum number of nodes that we would ever need to allocate and the
- other for the colors that we will return. we need one more slot than the number of colors requested, because the
- algorithm inserts every new color that it finds and only then does it check to see if we have too many colors and
- we need to reduce the octree.
-
- the standard way of working with octree nodes is to have eight pointers in each node to the various children of
- that node. however, in an effort to reduce the storage requirements (and not burden the memory manager with
- too many blocks), we have chosen to use indices into the nodeBase array for each of the children. a child of a node
- can either be a color or another node and since these two types of objects are different sizes and stored in
- different arrays, we use the convention of negative numbers to indicate that the bitwise not of the child index is
- an index into the color table and positive numbers to indicate that the child index is an index into the node table.
- there is also a special constant (emptyNode) to indicate that a child entry is empty.
-
- each node and color keeps an index to its parent node, which greatly speeds up the reduction process. nodes also
- keep a count of their children, although this isn’t as much of a win for the reduction process.
-
- the way the algorithm works is that for every color, we call AddColorToOctree, which walks down all the nodes,
- until it finds the correct slot for the color. to determine the correct slot, we use only the high byte of each
- component, which we sucessively shift as we walk through the tree, using the highest bit of each component to
- select which child of the node to look at. if the child node is empty and we haven’t reached our maximum level
- yet, we create a new node and continue the add process. if we have reached our maximum level, then we create
- a new color and save our color-to-add there. if the child entry points to an already existing color, then we add
- our new color to the accumulating totals in the color entry and return.
-
- after adding a new color, we check to see if the number of colors in the tree is greater than the number requested.
- if this is the case, then we call ReduceOctree, which in a very simplistic way, combines two existing color entries
- into one that spans a broader section of the RGB cube.
-
- when picture utilities asks us for the color table, we can return it directly out of our colorBase array, since the
- octree has been being trimmed as we go.
-
- much of the code for this method is concerned with the reduction process. reduction is a bit tricky since we don’t
- keep pointers to children and we don’t allow gaps in either our node structure or our color structure. this has the
- benefit of allowing us to avoid allocating or deallocating any memory while we are recording colors, but we have
- to have code to deal with things like removing a color (or a node) from the middle of the colorBase array. we do
- so by copying the last color (or node) over the item that we are removing and then updating that item’s parent to
- point to the new spot. if the item is a color, then we also need to walk the colorList for the correct level and re-
- link the chain of colors to skip the removed one.
-
- the colorList arrays are convenient in determining where to start combining nodes during reduction. there is an
- array for each level and when we need to reduce colors, we always start with the maximumLevel array (level
- eight) and we try to reduce the first item in it. if that color’s parent had more than one child, then we can save
- a color by combining all the children of this parent into a single averaged color and we imediately proceed to do
- so. if the parent has only one child, then we move to the next color in the colorList for that level. only when we
- are unable to reduce any colors in a given level do we move up to the colorList array for the previous level and
- try to reduce colors from it.
-
- when we move up a level, we must also remember to try reducing the next level’s colors by two levels, before
- actually giving up are proceeding up another level. for example, we might have 3 level 8 colors that can’t be
- reduced to level 7 (or at least we wouldn’t gain a color) and 5 level 7 nodes that also can’t be reduced. after
- checking the last level 7 node, we would look again at the level 8 nodes, this time trying to reduce them all the
- way up to level 6, where they would encompass sixty-four level 8 RGB cubes. if we can save a color by reducing
- a level 8 color two levels up to level six, we will do so before proceeding to the level 6 list and trying to reduce
- level 6 colors to level 5.
-
- there is lots of room for improvement in the algorithm that choses which colors to reduce. currently, we don’t
- look at all at the number of source codes combined into a color entry; this lets us preserve small splashes of a
- drasticly different color at the cost of muddying up the colors that make up the bulk of the image.
-
- note that we remove colors immediately when we combine them, but we only mark nodes as obsolete without
- removing them on the spot. this is solely because the ReduceNode routine is recursive and keeps which node
- it is working with on the stack. this would be a problem if while removing a node, we need to reorder the nodes
- that are referenced by different incarnations of ReduceNode. by marking all the nodes as obsolete, we can
- postpone removing them until no-one has any references (besides the tree structure itself) and it is safe to
- move nodes.
- */
- /*-------------------------------------------------------------------------------------------------------*/
-
-
- /* function prototypes for the main subroutines that picture utilities will call. */
-
- pascal short InitOctree(short colorsRequested, long *dataHandlePtr, short *bankType);
- pascal short RecordOctreeColors(long dataHandle, RGBColor *colorPtr, long colorCount, long *uniqueColorsPtr);
- pascal short CalcOctreeTable(long dataHandle, short colorsRequested, short *colorBankPtr, ColorSpec *resultPtr);
- pascal short KillOctree(long dataHandle);
-
-
-
- /* our main dispatcher. picture utilities will call this with the selector for which pick function to call in D0.w */
- void main(void)
- {
- asm {
- lsl.w #2, d0
- lea @table, a0
- jmp 0(a0, d0.w)
-
- @table jmp InitOctree
- jmp RecordOctreeColors
- jmp CalcOctreeTable
- jmp KillOctree
- }
- }
-
-
- /* these functions validate the main octree structure to make sure that all the nodes point to valid entries in either the
- node table or in the color table. they also make sure that each node’s (or color’s) parent field really does point to the
- node that contains them and they ensure that all the color lists (one for each level) contain only colors that are valid
- entries in the color table */
-
- #ifdef debugging
- static void ValidateNode(octree *tree, octreeNode *node)
- {
- short counter = 8;
- short nodeIndex;
-
- IfDebug(node->children > 8, "\ptoo many children in node");
- IfDebug(node->parent != emptyNode && node->parent >= tree->nodes, "\pinvalid node parent");
-
- nodeIndex = node - &tree->nodeBase[0];
- while( --counter >= 0 ) {
- short childIndex = node->leaf[counter];
- if( childIndex != emptyNode ) {
- if( childIndex >= 0 ) {
- octreeNode *child;
- IfDebug(childIndex >= tree->nodes, "\pinvalid node child");
- child = &tree->nodeBase[childIndex];
- if( child->children != obsoleteNode ) {
- IfDebug(child->parent != nodeIndex, "\pchild node doesnt belong to parent");
- ValidateNode(tree, child);
- }
- } else {
- octreeColor *child;
- childIndex = ~childIndex;
- IfDebug(childIndex >= tree->colors, "\pinvalid color child");
- child = &tree->colorBase[childIndex];
- IfDebug(child->parent != nodeIndex, "\pchild color doesnt belong to parent");
- IfDebug(child->level > maximumLevel, "\pcolor level is invalid");
- IfDebug(child->next != emptyNode && child->next >= tree->colors, "\pcolor next field is invalid");
- }
- }
- }
- }
-
- static void ValidateColorList(octree *tree, short colorIndex)
- {
- short level = -1;
- while( colorIndex != emptyNode ) {
- octreeColor *color;
- IfDebug(colorIndex >= tree->colors, "\pinvalid color in color list");
- color = &tree->colorBase[colorIndex];
- IfDebug(color->level > maximumLevel, "\pcolor level is invalid");
- if( level < 0 )
- level = color->level;
- IfDebug(color->level != level, "\pcolor not at same level as the rest of the list");
- colorIndex = color->next;
- }
- }
-
- static void ValidateOctree(octree *tree)
- {
- octreeNode *node = &tree->nodeBase[0];
- short counter;
-
- ++tree->validationCount;
- IfDebug(node->children == obsoleteNode, "\pthe top node cannot be obsolete");
- ValidateNode(tree, node);
-
- counter = maximumLevel + 1;
- while( --counter > 0 )
- ValidateColorList(tree, tree->colorList[counter]);
- }
- #endif
-
-
- /* this function is called to add each color to the octree */
-
- static void AddColorToOctree(octree *tree, RGBColor *inputColor)
- {
- char red = inputColor->red >> 8;
- char green = inputColor->green >> 8;
- char blue = inputColor->blue >> 8;
- octreeNode *node = &tree->nodeBase[0];
- short level = 0;
- short index;
-
- ValidateTree(tree);
- while( true ) {
- short *childPtr;
-
- ++level;
-
- /* use the red, green, and blue input components to determine which of the eight children of this node to look
- at. then shift the components left by one bit to leave them setup for the next time through this loop. */
-
- index = 0;
- if(red < 0) index += 4; red <<= 1;
- if(green < 0) index += 2; green <<= 1;
- if(blue < 0) index += 1; blue <<= 1;
-
- /* get a pointer to the child in this node that we are going to look at. */
-
- childPtr = &node->leaf[index];
- index = *childPtr;
-
- if( index == emptyNode ) {
-
- /* increment this node’s child count, since it now has children. then calculate the index of the parent node */
- ++node->children;
- index = node - &tree->nodeBase[0];
-
- if( level == maximumLevel ) {
- octreeColor *color;
-
- IfDebug(tree->colors >= tree->maximumColors, "\pno room to create another color");
-
- /* the child at this position was empty and we are at level eight (the deepest possible), so add the input
- color to the color table and set this child to “point” to this new color entry. note that indices that
- point to entries in the color table are negative to distinguish them from indices that point to entries
- in the node table. */
-
- *childPtr = ~tree->colors;
- color = &tree->colorBase[tree->colors];
- color->count = 1;
- color->totalRed = inputColor->red;
- color->totalGreen = inputColor->green;
- color->totalBlue = inputColor->blue;
-
- color->level = level;
- color->next = tree->colorList[level];
- color->parent = index;
- tree->colorList[level] = tree->colors;
- ++tree->colors;
- return;
- }
-
- IfDebug(tree->nodes >= tree->maximumNodes, "\pno room to create another node");
-
- /* create a new node here and set this child to “point” to this new color entry. next clear all the fields of
- the new node. */
-
- *childPtr = tree->nodes;
- node = &tree->nodeBase[tree->nodes];
- node->children = 0;
- node->parent = index;
- node->leaf[0] = emptyNode;
- node->leaf[1] = emptyNode;
- node->leaf[2] = emptyNode;
- node->leaf[3] = emptyNode;
- node->leaf[4] = emptyNode;
- node->leaf[5] = emptyNode;
- node->leaf[6] = emptyNode;
- node->leaf[7] = emptyNode;
- ++tree->nodes;
- continue;
-
- } else if( index < 0 ) {
- octreeColor *color = &tree->colorBase[~index];
-
- /* the child at this position was a color so add the input color to the total color for this entry and increment
- the count. we can use these values at the end of the process to calculate an average color for this entry.
- note that these totals will overflow when more than 65536 pixels with large components (greater than
- 65000) are all in this box; we aren’t going to worry about this, for now. */
-
- ++color->count;
- color->totalRed += inputColor->red;
- color->totalGreen += inputColor->green;
- color->totalBlue += inputColor->blue;
- return;
- }
-
- IfDebug(index >= tree->nodes, "\ppast the end of the octree");
- node = &tree->nodeBase[index];
- }
- }
-
-
- static void RemoveColorFromLevel(octree *tree, short colorIndex)
- {
- octreeColor *color = &tree->colorBase[colorIndex];
-
- IfDebug(colorIndex >= tree->colors, "\pcolor to remove doesnt exist");
-
- if( tree->colorList[color->level] == colorIndex )
- tree->colorList[color->level] = color->next;
- else {
- short index = tree->colorList[color->level];
-
- while( index != emptyNode ) {
- color = &tree->colorBase[index];
- IfDebug(index >= tree->colors, "\pcolor in color list doesnt exist");
- if( color->next == colorIndex ) {
- color->next = tree->colorBase[color->next].next;
- return;
- }
- index = color->next;
- }
-
- IfDebug(1, "\pcolor to remove is not in this level list");
- }
- }
-
-
- /* this function removes the color specified by newIndex from the octree. since the color table in the octree cannot have
- gaps, removing this color really consists of moving the last color in the octree to the position occupied by newIndex
- and then reducing the total color count. since the nodes in the octree reference this last color once somewhere, we
- must scan through all the nodes until we find the one that does reference it and update its leaf entry to index to the
- new position of this color. this function also keeps track of where the color pointed to by preserveColor moves to
- (if it does move) and it returns this new location. */
-
- static octreeColor *RemoveColor(octree *tree, short newIndex, octreeColor *preserveColor)
- {
- short oldIndex;
-
- ValidateTree(tree);
- RemoveColorFromLevel(tree, newIndex);
-
- /* if we are removing the last color, then there is no reordering to do, so simply return. */
-
- oldIndex = --tree->colors;
- if( oldIndex == newIndex )
- return preserveColor;
-
- IfDebug(newIndex > oldIndex, "\pattempting to remove a color that doesnt exist");
-
- /* if the color we are moving (the last color) is the one whose pointer we need to preserve, then reset its pointer
- to its new location. then copy the color structure from the old position to the new one. */
-
- if( &tree->colorBase[oldIndex] == preserveColor )
- preserveColor = &tree->colorBase[newIndex];
- tree->colorBase[newIndex] = tree->colorBase[oldIndex];
-
- /* look at the color we are moving (the last color) and get its level. then scan through all the colors in the list for
- this level looking for the one that we renumbered. when we find it, then we renumber it. */
-
- { octreeColor *color = &tree->colorBase[oldIndex];
- if( tree->colorList[color->level] == oldIndex ) {
- tree->colorList[color->level] = newIndex;
- } else {
- short levelIndex = tree->colorList[color->level];
- while( levelIndex != emptyNode ) {
- color = &tree->colorBase[levelIndex];
- IfDebug(levelIndex > tree->colors, "\pcolor in color list doesnt exist");
- if( color->next == oldIndex ) {
- color->next = newIndex;
- break;
- }
- levelIndex = color->next;
- }
- }
- }
-
- /* look at the color we are moving (the last color) and get its parent node. then scan through all the children of this
- parent to find the entry that points to the old location and update it to contain the index of the new location. */
-
- { octreeColor *color = &tree->colorBase[newIndex];
-
- if( color->parent != emptyNode ) {
- octreeNode *node = &tree->nodeBase[color->parent];
- short counter = 8;
-
- IfDebug(color->parent >= tree->nodes, "\pcolor has an invalid parent");
- IfDebug(node->children == obsoleteNode, "\pcolors parent is obsolete");
-
- oldIndex = ~oldIndex;
- while( --counter >= 0 ) {
- if( node->leaf[counter] == oldIndex ) {
- node->leaf[counter] = ~newIndex;
- ValidateTree(tree);
- return preserveColor;
- }
- }
- IfDebug(1, "\pcant find last color in its parent node");
- }
- }
-
- return preserveColor;
- }
-
-
- static octreeColor *ReduceNode(octree *tree, octreeNode *base, octreeColor *resultColor)
- {
- short index;
- short counter = 8;
-
- ValidateTree(tree);
- while( --counter >= 0 ) {
- index = base->leaf[counter];
- if( index == emptyNode )
- continue;
- if( index >= 0 ) {
- IfDebug(index >= tree->nodes, "\pattempting to reduce a node that doesnt exist");
- resultColor = ReduceNode(tree, &tree->nodeBase[index], resultColor);
- } else {
- octreeColor *newColor = &tree->colorBase[~index];
- IfDebug(~index >= tree->colors, "\pattempting to remove a color that doesnt exist");
- if( resultColor != newColor ) {
- base->leaf[counter] = emptyNode;
- newColor->parent = emptyNode;
- resultColor->count += newColor->count;
- resultColor->totalRed += newColor->totalRed;
- resultColor->totalGreen += newColor->totalGreen;
- resultColor->totalBlue += newColor->totalBlue;
- resultColor = RemoveColor(tree, ~index, resultColor);
- }
- }
- }
- base->children = obsoleteNode;
- ValidateTree(tree);
- return resultColor;
- }
-
-
- static void RemoveObsoleteNodes(octree *tree)
- {
- octreeNode *outerNode = &tree->nodeBase[0];
- short outerNodes = tree->nodes;
-
- ValidateTree(tree);
-
- while( --outerNodes >= 0 ) {
- if( outerNode->children == obsoleteNode ) {
- octreeNode *node = outerNode;
- octreeNode *parent;
- short newIndex = outerNode - &tree->nodeBase[0];
- short oldIndex;
- short counter;
-
- while( node->children == obsoleteNode ) {
- oldIndex = (--outerNodes, --tree->nodes);
- if( outerNodes < 0 ) {
- ValidateTree(tree);
- return;
- }
- node = &tree->nodeBase[oldIndex];
- }
-
- parent = &tree->nodeBase[node->parent];
-
- counter = 8;
- while( --counter >= 0 ) {
- if( parent->leaf[counter] == oldIndex ) {
- parent->leaf[counter] = newIndex;
- goto fixChildren;
- }
- }
- IfDebug(1, "\pcant find the node we are moving in its parents list of children");
- fixChildren:
- counter = 8;
- while( --counter >= 0 ) {
- short index = node->leaf[counter];
- if( index == emptyNode )
- continue;
- if( index >= 0 ) {
- octreeNode *child = &tree->nodeBase[index];
- IfDebug(child->parent != oldIndex, "\pchild does not point back to correct parent");
- child->parent = newIndex;
- } else {
- octreeColor *child = &tree->colorBase[~index];
- IfDebug(child->parent != oldIndex, "\pchild does not point back to correct parent");
- child->parent = newIndex;
- }
- }
-
- tree->nodeBase[newIndex] = tree->nodeBase[oldIndex];
- }
- next: ++outerNode;
- }
- ValidateTree(tree);
- }
-
-
- static void ReduceOctree(octree *tree)
- {
- octreeColor *color;
- octreeNode *node;
- short level;
- short index;
-
- if( tree->colors < tree->maximumColors )
- return;
-
- ValidateTree(tree);
- level = maximumLevel;
- while( level > 0 ) {
- short innerLevel = level;
-
- while( innerLevel <= maximumLevel ) {
- index = tree->colorList[innerLevel];
- while( index != emptyNode ) {
- short parentIndex;
-
- IfDebug(index >= tree->colors, "\pinvalid color in the color list");
- color = &tree->colorBase[index];
- parentIndex = color->parent;
- IfDebug(parentIndex >= tree->nodes, "\pcolor has invalid parent");
- node = &tree->nodeBase[parentIndex];
-
- { short tempLevel = innerLevel;
- while( tempLevel > level ) {
- parentIndex = node->parent;
- IfDebug(parentIndex >= tree->nodes, "\pnode has invalid parent");
- node = &tree->nodeBase[parentIndex];
- --tempLevel;
- }
- }
-
- if( node->children > 1 ) {
- octreeNode *parent = &tree->nodeBase[node->parent];
- short counter = 8;
- while( --counter >= 0 ) {
- if( parent->leaf[counter] == parentIndex ) {
- short colorIndex;
-
- /* orphan the color from its parent */
-
- { octreeNode *colorParent = &tree->nodeBase[color->parent];
- short counter = 8;
- colorIndex = ~(color - &tree->colorBase[0]);
- while( --counter >= 0 ) {
- if( colorParent->leaf[counter] == colorIndex ) {
- colorParent->leaf[counter] = emptyNode;
- goto orphanColor;
- }
- }
- IfDebug(1, "\pcouldnt find color in parent");
- }
- orphanColor: color->parent = emptyNode;
- ValidateTree(tree);
-
- color = ReduceNode(tree, node, color);
- ValidateTree(tree);
- colorIndex = color - &tree->colorBase[0];
- RemoveColorFromLevel(tree, colorIndex);
- color->level = level - 1;
- color->parent = parent - &tree->nodeBase[0];
- parent->leaf[counter] = ~colorIndex;
- color->next = tree->colorList[level - 1];
- tree->colorList[level - 1] = colorIndex;
- RemoveObsoleteNodes(tree);
- return;
- }
- }
- IfDebug(1, "\pcant find node in parent");
- }
- index = color->next;
- }
- ++innerLevel;
- }
-
- --level;
- }
-
- IfDebug(1, "\punable to reduce the octree");
- }
-
-
- pascal short InitOctree(short colorsRequested, long *dataHandlePtr, short *bankType)
- {
- octree *tree;
- octreeNode *node;
- Handle dataHandle, tempHandle;
- short counter;
-
- if( colorsRequested < 4 || colorsRequested > 256 )
- return colorsRequestedErr;
-
- dataHandle = NewHandleClear(sizeof(octree));
- if( dataHandle == nil )
- return memFullErr;
-
- HLock(dataHandle);
- tree = *(octree **)dataHandle;
- counter = maximumLevel + 1;
- while( --counter >= 0 )
- tree->colorList[counter] = emptyNode;
-
- tree->maximumNodes = 1 + 8 + 64; /* for level 0, 1, and 2. If the maximumLevel is three, then the next level will be colors */
- if( maximumLevel > 3 )
- tree->maximumNodes += (colorsRequested + 1) * (maximumLevel - 3);
- tempHandle = NewHandle(tree->maximumNodes * sizeof(octreeNode));
- HLock(tempHandle);
- tree->nodeBase = *(octreeNode **)tempHandle;
- tree->nodes = 1;
- node = &tree->nodeBase[0];
- node->children = 0;
- node->parent = emptyNode;
- counter = 8;
- while( --counter >= 0 )
- node->leaf[counter] = emptyNode;
-
- tree->maximumColors = colorsRequested + 1;
- tempHandle = NewHandle(tree->maximumColors * sizeof(octreeColor));
- HLock(tempHandle);
- tree->colorBase = *(octreeColor **)tempHandle;
-
- HUnlock(dataHandle);
-
- *dataHandlePtr = (long)dataHandle;
- *bankType = ColorBankIsCustom;
- return noErr;
- }
-
-
- pascal short KillOctree(long dataHandle)
- {
- octree *tree = *(octree **)dataHandle;
-
- DisposeHandle(RecoverHandle(tree->colorBase));
- DisposeHandle(RecoverHandle(tree->nodeBase));
- DisposeHandle((Handle)dataHandle);
- return noErr;
- }
-
-
- pascal short RecordOctreeColors(long dataHandle, RGBColor *colorPtr, long colorCount, long *uniqueColorsPtr)
- {
- octree *tree;
-
- HLock((Handle)dataHandle);
- tree = *(octree **)dataHandle;
-
- while( --colorCount >= 0 ) {
- AddColorToOctree(tree, colorPtr++);
- if( tree->colors == tree->maximumColors )
- ReduceOctree(tree);
- }
-
- /* picture utilities actually uses this value to clip the palette entries to either the number of colors requested or
- the number of unique colors in the picture, whichever is smaller. if we don’t set this field, then it will be zero
- and picture utilities will always generate a palette with zero colors! */
-
- *uniqueColorsPtr = tree->colors;
-
- HUnlock((Handle)dataHandle);
- return noErr;
- }
-
-
- static unsigned short Divide(register long component, register long count)
- {
- asm {
- divu.l count, component
- move.w component, d0
- }
- }
-
- pascal short CalcOctreeTable(long dataHandle, short colorsRequested, short *colorBankPtr, ColorSpec *resultPtr)
- {
- octree *tree;
- octreeColor *color;
- short index;
- short uniqueColors;
-
- HLock((Handle)dataHandle);
- tree = *(octree **)dataHandle;
- color = &tree->colorBase[0];
- uniqueColors = tree->colors;
-
- for(index=0; index < colorsRequested; ++index) {
- resultPtr->value = index;
- if( --uniqueColors >= 0 ) {
- resultPtr->rgb.red = Divide(color->totalRed, color->count);
- resultPtr->rgb.green = Divide(color->totalGreen, color->count);
- resultPtr->rgb.blue = Divide(color->totalBlue, color->count);
- ++color;
- } else {
- resultPtr->rgb.red = 0;
- resultPtr->rgb.green = 0;
- resultPtr->rgb.blue = 0;
- }
- ++resultPtr;
- }
-
- HUnlock((Handle)dataHandle);
- return noErr;
- }
-